<html>
<head><meta charset="utf-8"><title>Design question about the Visitor pattern · t-compiler · Zulip Chat Archive</title></head>
<h2>Stream: <a href="https://rust-lang.github.io/zulip_archive/stream/131828-t-compiler/index.html">t-compiler</a></h2>
<h3>Topic: <a href="https://rust-lang.github.io/zulip_archive/stream/131828-t-compiler/topic/Design.20question.20about.20the.20Visitor.20pattern.html">Design question about the Visitor pattern</a></h3>

<hr>

<base href="https://rust-lang.zulipchat.com">

<head><link href="https://rust-lang.github.io/zulip_archive/style.css" rel="stylesheet"></head>

<a name="217380994"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/131828-t-compiler/topic/Design%20question%20about%20the%20Visitor%20pattern/near/217380994" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Robin Moussu <a href="https://rust-lang.github.io/zulip_archive/stream/131828-t-compiler/topic/Design.20question.20about.20the.20Visitor.20pattern.html#217380994">(Nov 20 2020 at 10:00)</a>:</h4>
<p>I am <strong>not</strong> advocating for changes. I think that their are some advantages to the current design that I fail to understand, and I would like to get enlighten!</p>
<p>In MIR, you have the <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/visit/trait.Visitor.html#method.visit_rvalue"><code>Visitor</code></a> trait. This traits is extremely useful to visit MIR. But I don't understand why it's a trait with overwriddable methods instead of being free function that takes a closure.</p>
<p>Let's take an example: extracting all the constant used in a function:</p>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="k">fn</span> <span class="nf">extract_constant</span><span class="o">&lt;'</span><span class="na">tcx</span><span class="o">&gt;</span><span class="p">(</span><span class="n">mir</span>: <span class="kp">&amp;</span><span class="o">'</span><span class="na">tcx</span> <span class="nc">mir</span>::<span class="n">Body</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">HashSet</span><span class="o">&lt;&amp;'</span><span class="na">tcx</span><span class="w"> </span><span class="n">rustc_middle</span>::<span class="n">ty</span>::<span class="n">Const</span><span class="o">&lt;'</span><span class="na">tcx</span><span class="o">&gt;&gt;</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="cp">#[derive(Default)]</span><span class="w"></span>
<span class="w">    </span><span class="k">struct</span> <span class="nc">Constants</span><span class="o">&lt;'</span><span class="na">tcx</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="n">constants</span>: <span class="nc">HashSet</span><span class="o">&lt;&amp;'</span><span class="na">tcx</span><span class="w"> </span><span class="n">rustc_middle</span>::<span class="n">ty</span>::<span class="n">Const</span><span class="o">&lt;'</span><span class="na">tcx</span><span class="o">&gt;&gt;</span><span class="p">,</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="k">impl</span><span class="o">&lt;'</span><span class="na">tcx</span><span class="o">&gt;</span><span class="w"> </span><span class="n">mir</span>::<span class="n">visit</span>::<span class="n">Visitor</span><span class="o">&lt;'</span><span class="na">tcx</span><span class="o">&gt;</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">Constants</span><span class="o">&lt;'</span><span class="na">tcx</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="k">fn</span> <span class="nf">visit_constant</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span><span class="w"> </span><span class="bp">self</span><span class="p">,</span><span class="w"> </span><span class="n">constant</span>: <span class="kp">&amp;</span><span class="nc">mir</span>::<span class="n">Constant</span><span class="o">&lt;'</span><span class="na">tcx</span><span class="o">&gt;</span><span class="p">,</span><span class="w"> </span><span class="n">_</span>: <span class="nc">mir</span>::<span class="n">Location</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">            </span><span class="bp">self</span><span class="p">.</span><span class="n">constants</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="n">constant</span><span class="p">.</span><span class="n">literal</span><span class="p">);</span><span class="w"></span>
<span class="w">        </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>

<span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">search_constants</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Constants</span>::<span class="n">default</span><span class="p">();</span><span class="w"></span>
<span class="w">    </span><span class="n">search_constants</span><span class="p">.</span><span class="n">visit_body</span><span class="p">(</span><span class="n">mir</span><span class="p">);</span><span class="w"></span>

<span class="w">    </span><span class="n">search_constants</span><span class="p">.</span><span class="n">constants</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>
<p>This example is relatively simple. For example it doesn't capture any variable from <code>extract_constant</code>. If instead <code>mir::Body</code> had <code>visit_*</code> methods that took a closure, it would become:</p>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="k">fn</span> <span class="nf">extract_constant</span><span class="o">&lt;'</span><span class="na">tcx</span><span class="o">&gt;</span><span class="p">(</span><span class="n">mir</span>: <span class="kp">&amp;</span><span class="o">'</span><span class="na">tcx</span> <span class="nc">mir</span>::<span class="n">Body</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">HashSet</span><span class="o">&lt;&amp;'</span><span class="na">tcx</span><span class="w"> </span><span class="n">rustc_middle</span>::<span class="n">ty</span>::<span class="n">Const</span><span class="o">&lt;'</span><span class="na">tcx</span><span class="o">&gt;&gt;</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">constants</span>: <span class="nc">HashSet</span><span class="o">&lt;&amp;</span><span class="n">rustc_middle</span>::<span class="n">ty</span>::<span class="n">Const</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">HashSet</span>::<span class="n">new</span><span class="p">()</span><span class="w"></span>
<span class="w">    </span><span class="n">mir</span><span class="p">.</span><span class="n">visit_constant</span><span class="p">(</span><span class="o">|</span><span class="n">constant</span>: <span class="kp">&amp;</span><span class="nc">mir</span>::<span class="n">Constant</span><span class="o">&lt;'</span><span class="na">tcx</span><span class="o">&gt;</span><span class="p">,</span><span class="w"> </span><span class="n">_</span>: <span class="nc">mir</span>::<span class="n">Location</span><span class="o">|</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="n">constants</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="n">constant</span><span class="p">.</span><span class="n">literal</span><span class="p">);</span><span class="w"></span>
<span class="w">    </span><span class="p">});</span><span class="w"></span>
<span class="w">    </span><span class="n">constants</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>
<p>In addition to being much shorter, and (IMHO) readable, it's also much easier to capture variables from <code>extract_body</code> since you don't have to create a new field in the <code>Constant</code> struct, then pass them in its constructor.</p>
<p>Given how much more simple to use the closure version seems to be, what are the advantages of implementing a trait?</p>



<a name="217395574"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/131828-t-compiler/topic/Design%20question%20about%20the%20Visitor%20pattern/near/217395574" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jonas Schievink  [he/him] <a href="https://rust-lang.github.io/zulip_archive/stream/131828-t-compiler/topic/Design.20question.20about.20the.20Visitor.20pattern.html#217395574">(Nov 20 2020 at 12:41)</a>:</h4>
<p>how would the closure API work if I want to visit both statements and terminators?</p>



<a name="217399387"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/131828-t-compiler/topic/Design%20question%20about%20the%20Visitor%20pattern/near/217399387" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Robin Moussu <a href="https://rust-lang.github.io/zulip_archive/stream/131828-t-compiler/topic/Design.20question.20about.20the.20Visitor.20pattern.html#217399387">(Nov 20 2020 at 13:20)</a>:</h4>
<p>If you need to visit both at the same time, it doesn't work with this simplistic API. If you just want to extract something from the statement then from the terminators you can always visit it two times. But I guess that some performance is left on the table.</p>
<p>A more powerful closure-based API would be based on the builder pattern. This would allow to visit both at the same time.</p>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="n">mir</span><span class="p">.</span><span class="n">create_visitor</span><span class="p">()</span><span class="w"></span>
<span class="w">    </span><span class="p">.</span><span class="n">constants</span><span class="p">(</span><span class="o">|</span><span class="n">constant</span>: <span class="kp">&amp;</span><span class="nc">mir</span>::<span class="n">Constant</span><span class="o">&lt;'</span><span class="na">tcx</span><span class="o">&gt;</span><span class="p">,</span><span class="w"> </span><span class="n">_</span>: <span class="nc">mir</span>::<span class="n">Location</span><span class="o">|</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="c1">// ...</span>
<span class="w">    </span><span class="p">})</span><span class="w"></span>
<span class="w">    </span><span class="p">.</span><span class="n">terminators</span><span class="p">(</span><span class="o">|</span><span class="n">terminator</span>: <span class="kp">&amp;</span><span class="nc">mir</span>::<span class="n">Terminator</span><span class="o">&lt;'</span><span class="na">tcx</span><span class="o">&gt;</span><span class="p">,</span><span class="w"> </span><span class="n">location</span>: <span class="nc">mir</span>::<span class="n">Location</span><span class="o">|</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="c1">// ...</span>
<span class="w">    </span><span class="p">})</span><span class="w"></span>
<span class="w">    </span><span class="p">.</span><span class="n">visit</span><span class="p">();</span><span class="w"></span>
</code></pre></div>



<a name="217399579"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/131828-t-compiler/topic/Design%20question%20about%20the%20Visitor%20pattern/near/217399579" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jonas Schievink  [he/him] <a href="https://rust-lang.github.io/zulip_archive/stream/131828-t-compiler/topic/Design.20question.20about.20the.20Visitor.20pattern.html#217399579">(Nov 20 2020 at 13:22)</a>:</h4>
<p>But it wouldn't let you share mutable state between the closures</p>



<a name="217402374"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/131828-t-compiler/topic/Design%20question%20about%20the%20Visitor%20pattern/near/217402374" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Robin Moussu <a href="https://rust-lang.github.io/zulip_archive/stream/131828-t-compiler/topic/Design.20question.20about.20the.20Visitor.20pattern.html#217402374">(Nov 20 2020 at 13:47)</a>:</h4>
<p>The issue is <a href="https://play.rust-lang.org/?version=stable&amp;mode=release&amp;edition=2018&amp;gist=dfc32eb4f2a588b5bfb80365d56fe551">this</a>, isn't it? I guess there is currently no way to tell the borrow checker that both closure can't be run at the same time on two different threads? I tried to play with <code>?Sync</code> without success.</p>



<a name="217402593"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/131828-t-compiler/topic/Design%20question%20about%20the%20Visitor%20pattern/near/217402593" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jonas Schievink  [he/him] <a href="https://rust-lang.github.io/zulip_archive/stream/131828-t-compiler/topic/Design.20question.20about.20the.20Visitor.20pattern.html#217402593">(Nov 20 2020 at 13:49)</a>:</h4>
<p>There's also the issue of not being able to precisely control which nested data is processed by the visitor</p>



<a name="217402641"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/131828-t-compiler/topic/Design%20question%20about%20the%20Visitor%20pattern/near/217402641" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Jonas Schievink  [he/him] <a href="https://rust-lang.github.io/zulip_archive/stream/131828-t-compiler/topic/Design.20question.20about.20the.20Visitor.20pattern.html#217402641">(Nov 20 2020 at 13:49)</a>:</h4>
<p>You might want to visit MIR locals, but skip a few statements or terminators whose local usage you aren't interested in</p>



<a name="217403671"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/131828-t-compiler/topic/Design%20question%20about%20the%20Visitor%20pattern/near/217403671" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> marmeladema <a href="https://rust-lang.github.io/zulip_archive/stream/131828-t-compiler/topic/Design.20question.20about.20the.20Visitor.20pattern.html#217403671">(Nov 20 2020 at 13:58)</a>:</h4>
<p>Could this "simple" API be built around the current <code>Visitor</code> trait?</p>



<a name="217404191"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/131828-t-compiler/topic/Design%20question%20about%20the%20Visitor%20pattern/near/217404191" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oli <a href="https://rust-lang.github.io/zulip_archive/stream/131828-t-compiler/topic/Design.20question.20about.20the.20Visitor.20pattern.html#217404191">(Nov 20 2020 at 14:02)</a>:</h4>
<p>I've definitely wanted a simpler API than having to create a struct and implement the trait before. Not sure if it's worth it. We'd have to look at all impls of <code>Visitor</code> to see whether a large enough percentage could be replaced. I mean, all it takes is to implement the trait for a struct that wraps a closure and reexpose that struct (or a helper function using that struct). We could probably even autogenerate these from the trait definition</p>



<a name="217404248"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/131828-t-compiler/topic/Design%20question%20about%20the%20Visitor%20pattern/near/217404248" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> oli <a href="https://rust-lang.github.io/zulip_archive/stream/131828-t-compiler/topic/Design.20question.20about.20the.20Visitor.20pattern.html#217404248">(Nov 20 2020 at 14:02)</a>:</h4>
<p>but yea, when you want multiple closures, you should just move to using a struct instead</p>



<a name="217406186"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/131828-t-compiler/topic/Design%20question%20about%20the%20Visitor%20pattern/near/217406186" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Robin Moussu <a href="https://rust-lang.github.io/zulip_archive/stream/131828-t-compiler/topic/Design.20question.20about.20the.20Visitor.20pattern.html#217406186">(Nov 20 2020 at 14:19)</a>:</h4>
<blockquote>
<p>There's also the issue of not being able to precisely control which nested data is processed by the visitor. You might want to visit MIR locals, but skip a few statements or terminators whose local usage you aren't interested in</p>
</blockquote>
<p>I'm not sure I understand, how does the current API helps in that regards.</p>
<blockquote>
<p>Could this "simple" API be built around the current Visitor trait?</p>
</blockquote>
<p>Definitively yes, and it's even relatively simple to do. You just need to create a structure that takes a closure at parameter, then create a structure with this closure as a field, and then implement the <code>Visitor</code> trait for this struct that delegate the work to the closure. (I  didn't saw that <span class="user-mention" data-user-id="124288">@oli</span> already explained it).</p>
<blockquote>
<p>but yea, when you want multiple closures, you should just move to using a struct instead</p>
</blockquote>
<p>Only if you want to borrow the same thing mutably in multiple closures. Otherwise we can use the builder pattern that I described above.</p>



<a name="217426579"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/131828-t-compiler/topic/Design%20question%20about%20the%20Visitor%20pattern/near/217426579" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Daniel Henry-Mantilla <a href="https://rust-lang.github.io/zulip_archive/stream/131828-t-compiler/topic/Design.20question.20about.20the.20Visitor.20pattern.html#217426579">(Nov 20 2020 at 16:43)</a>:</h4>
<p>To capture common <code>&amp;mut</code> state:</p>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="n">mir</span><span class="p">.</span><span class="n">create_visitor</span><span class="p">()</span><span class="w"></span>
<span class="w">    </span><span class="p">.</span><span class="n">with_state</span><span class="p">(</span><span class="mi">0_</span><span class="k">usize</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="p">.</span><span class="n">constants</span><span class="p">(</span><span class="o">|</span><span class="n">state</span>: <span class="kp">&amp;</span><span class="nc">mut</span><span class="w"> </span><span class="n">_</span><span class="p">,</span><span class="w"> </span><span class="n">constant</span>: <span class="kp">&amp;</span><span class="nc">mir</span>::<span class="n">Constant</span><span class="o">&lt;'</span><span class="na">tcx</span><span class="o">&gt;</span><span class="p">,</span><span class="w"> </span><span class="n">_</span>: <span class="nc">mir</span>::<span class="n">Location</span><span class="o">|</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="o">*</span><span class="n">state</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span><span class="w"></span>
<span class="w">    </span><span class="p">})</span><span class="w"></span>
<span class="w">    </span><span class="p">.</span><span class="n">terminators</span><span class="p">(</span><span class="o">|</span><span class="n">state</span>: <span class="kp">&amp;</span><span class="nc">mut</span><span class="w"> </span><span class="n">_</span><span class="p">,</span><span class="w"> </span><span class="n">terminator</span>: <span class="kp">&amp;</span><span class="nc">mir</span>::<span class="n">Terminator</span><span class="o">&lt;'</span><span class="na">tcx</span><span class="o">&gt;</span><span class="p">,</span><span class="w"> </span><span class="n">location</span>: <span class="nc">mir</span>::<span class="n">Location</span><span class="o">|</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="o">*</span><span class="n">state</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span><span class="w"></span>
<span class="w">    </span><span class="p">})</span><span class="w"></span>
<span class="w">    </span><span class="p">.</span><span class="n">visit</span><span class="p">()</span><span class="cm">/* : State */</span><span class="p">;</span><span class="w"></span>
</code></pre></div>
<ul>
<li>(This looks awfully close to folding).</li>
</ul>
<p>I don't know if the generalized visitor builder is really worth it, but I think that having <code>impl Visitor</code> for <em>some</em> closures that only one to visit one specific node type is already quite useful and ergonomic <span aria-label="smile" class="emoji emoji-1f642" role="img" title="smile">:smile:</span></p>



<a name="217431284"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/131828-t-compiler/topic/Design%20question%20about%20the%20Visitor%20pattern/near/217431284" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Robin Moussu <a href="https://rust-lang.github.io/zulip_archive/stream/131828-t-compiler/topic/Design.20question.20about.20the.20Visitor.20pattern.html#217431284">(Nov 20 2020 at 17:15)</a>:</h4>
<p>That's amazing! (for those interested: <a href="https://play.rust-lang.org/?version=stable&amp;mode=release&amp;edition=2018&amp;gist=44c16ff4273d8e54341e115d2d8d9a2b">playground</a>).</p>



<a name="217436518"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/131828-t-compiler/topic/Design%20question%20about%20the%20Visitor%20pattern/near/217436518" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Daniel Henry-Mantilla <a href="https://rust-lang.github.io/zulip_archive/stream/131828-t-compiler/topic/Design.20question.20about.20the.20Visitor.20pattern.html#217436518">(Nov 20 2020 at 17:56)</a>:</h4>
<p>It would be even better with structural records <span aria-label="pray" class="emoji emoji-1f64f" role="img" title="pray">:pray:</span></p>



<a name="217437148"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/131828-t-compiler/topic/Design%20question%20about%20the%20Visitor%20pattern/near/217437148" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Daniel Henry-Mantilla <a href="https://rust-lang.github.io/zulip_archive/stream/131828-t-compiler/topic/Design.20question.20about.20the.20Visitor.20pattern.html#217437148">(Nov 20 2020 at 18:01)</a>:</h4>
<div class="codehilite" data-code-language="Rust"><pre><span></span><code><span class="kd">let</span><span class="w"> </span><span class="n">count_1</span>: <span class="kt">usize</span> <span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"></span>
<span class="kd">let</span><span class="w"> </span><span class="n">count_2</span>: <span class="kt">usize</span> <span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"></span>
<span class="kd">let</span><span class="w"> </span><span class="n">state</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Visit</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="n">state</span>: <span class="nc">__</span><span class="o">!</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="n">count_1</span><span class="p">,</span><span class="w"></span>
<span class="w">        </span><span class="n">count_2</span><span class="p">,</span><span class="w"></span>
<span class="w">    </span><span class="p">},</span><span class="w"></span>
<span class="w">    </span><span class="n">f1</span>: <span class="o">|</span><span class="n">state</span><span class="p">,</span><span class="w"> </span><span class="n">s1</span>: <span class="kp">&amp;</span><span class="nc">S1</span><span class="o">|</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="n">state</span><span class="p">.</span><span class="n">count_1</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">s1</span><span class="p">.</span><span class="mi">0</span><span class="p">;</span><span class="w"></span>
<span class="w">        </span><span class="n">state</span><span class="p">.</span><span class="n">count_2</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">s1</span><span class="p">.</span><span class="mi">0</span><span class="p">;</span><span class="w"></span>
<span class="w">    </span><span class="p">},</span><span class="w"></span>
<span class="w">    </span><span class="n">f2</span>: <span class="o">|</span><span class="n">state</span><span class="p">,</span><span class="w"> </span><span class="n">s2</span>: <span class="kp">&amp;</span><span class="nc">S2</span><span class="o">|</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="n">state</span><span class="p">.</span><span class="n">count_1</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">s2</span><span class="p">.</span><span class="mi">0</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">10</span><span class="p">;</span><span class="w"></span>
<span class="w">        </span><span class="n">state</span><span class="p">.</span><span class="n">count_2</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">s2</span><span class="p">.</span><span class="mi">0</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">100</span><span class="p">;</span><span class="w"></span>
<span class="w">    </span><span class="p">},</span><span class="w"></span>
<span class="p">}.</span><span class="n">visit</span><span class="p">(</span><span class="o">&amp;</span><span class="n">data</span><span class="p">);</span><span class="w"></span>
<span class="n">assert_eq</span><span class="o">!</span><span class="p">(</span><span class="n">state</span><span class="p">.</span><span class="n">count_1</span><span class="p">,</span><span class="w"> </span><span class="mi">110</span><span class="p">);</span><span class="w"></span>
<span class="n">assert_eq</span><span class="o">!</span><span class="p">(</span><span class="n">state</span><span class="p">.</span><span class="n">count_2</span><span class="p">,</span><span class="w"> </span><span class="mi">1010</span><span class="p">);</span><span class="w"></span>
</code></pre></div>
<ul>
<li><a href="https://play.rust-lang.org/?version=stable&amp;mode=release&amp;edition=2018&amp;gist=0a03fea18a9ff4bd511f75d5607d1f93">Playground</a></li>
</ul>



<a name="217448734"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/131828-t-compiler/topic/Design%20question%20about%20the%20Visitor%20pattern/near/217448734" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Robin Moussu <a href="https://rust-lang.github.io/zulip_archive/stream/131828-t-compiler/topic/Design.20question.20about.20the.20Visitor.20pattern.html#217448734">(Nov 20 2020 at 19:34)</a>:</h4>
<p>It took me way too much time to understand what you did with that macro, but it's amazing!<br>
Is your macro available somewhere on <a href="http://crates.io">crates.io</a>? Searching "structural record" on <a href="http://lib.rs">lib.rs</a> does returns anything.</p>



<a name="217475753"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/131828-t-compiler/topic/Design%20question%20about%20the%20Visitor%20pattern/near/217475753" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Daniel Henry-Mantilla <a href="https://rust-lang.github.io/zulip_archive/stream/131828-t-compiler/topic/Design.20question.20about.20the.20Visitor.20pattern.html#217475753">(Nov 21 2020 at 00:35)</a>:</h4>
<p>I have just stumbled upon <a href="https://lib.rs/crates/anon">https://lib.rs/crates/anon</a>, which is, modulo the optional (<code>: val</code>) specifier, literally the same as my macro, but from 2016 <span aria-label="big smile" class="emoji emoji-1f604" role="img" title="big smile">:big_smile:</span> For more advanced ones that allow to express in the type / trait system that a structure contains some field (so as to be able to have a function accept all the structures with the same named fields), there is <a href="https://docs.rs/structural">https://docs.rs/structural</a>, and, related to it, there is also <a href="https://docs.rs/frunk">https://docs.rs/frunk</a>.</p>



<a name="217540717"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/131828-t-compiler/topic/Design%20question%20about%20the%20Visitor%20pattern/near/217540717" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Robin Moussu <a href="https://rust-lang.github.io/zulip_archive/stream/131828-t-compiler/topic/Design.20question.20about.20the.20Visitor.20pattern.html#217540717">(Nov 22 2020 at 08:17)</a>:</h4>
<p>Btw, if I create a PR to rustc, can I add a dependency to such crate?</p>



<a name="217543201"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/131828-t-compiler/topic/Design%20question%20about%20the%20Visitor%20pattern/near/217543201" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> lqd <a href="https://rust-lang.github.io/zulip_archive/stream/131828-t-compiler/topic/Design.20question.20about.20the.20Visitor.20pattern.html#217543201">(Nov 22 2020 at 09:34)</a>:</h4>
<p>I guess it can depend on a case by case basis, but IMO it's probably better not to add dependencies if you can avoid it: there's a higher bar, costs, and risks than on a regular project (licensing, maintenance, repo and <a href="http://crates.io">crates.io</a> access, security, etc)</p>



<a name="217544336"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/131828-t-compiler/topic/Design%20question%20about%20the%20Visitor%20pattern/near/217544336" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Robin Moussu <a href="https://rust-lang.github.io/zulip_archive/stream/131828-t-compiler/topic/Design.20question.20about.20the.20Visitor.20pattern.html#217544336">(Nov 22 2020 at 10:10)</a>:</h4>
<p>Does this include dev-dependencies to give better examples in the documentation?</p>



<hr><p>Last updated: Aug 07 2021 at 22:04 UTC</p>
</html>